package com.xbongbong.pro.message.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.message.domain.entity.PushSetEntity;
import com.xbongbong.paas.enums.EnableEnum;
import com.xbongbong.paas.log.MongoLogHelp;
import com.xbongbong.paas.log.constant.LogMemoConstant;
import com.xbongbong.paas.log.entity.OperateLogEntity;
import com.xbongbong.paas.log.model.OperateLogModel;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.DateUtil;
import com.xbongbong.paas.toolbox.util.JsonHelperUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.log.pojo.DetailLogPojo;
import com.xbongbong.pro.message.enums.MessageMenuTypeEnum;
import com.xbongbong.pro.message.enums.PushTypeEnum;
import com.xbongbong.pro.message.model.PushSetModel;
import com.xbongbong.pro.message.pojo.MessageMenuPojo;
import com.xbongbong.pro.message.pojo.dto.MessageSetEnableDTO;
import com.xbongbong.pro.message.pojo.dto.MessageSetMenuListDTO;
import com.xbongbong.pro.message.pojo.dto.MessageSetSaveDTO;
import com.xbongbong.pro.message.pojo.vo.MessageSetEnableVO;
import com.xbongbong.pro.message.pojo.vo.MessageSetMenuListVO;
import com.xbongbong.pro.message.pojo.vo.MessageSetSaveVO;
import com.xbongbong.pro.message.service.MessageSetService;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.enums.OperateModuleTypeEnum;
import com.xbongbong.saas.enums.OperateTypeEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.service.toolbox.help.LogHelp;
import com.xbongbong.sys.domain.entity.CompanyEntity;
import com.xbongbong.sys.domain.entity.DepartmentEntity;
import com.xbongbong.sys.domain.entity.UserDepartmentEntity;
import com.xbongbong.sys.domain.entity.UserEntity;
import com.xbongbong.sys.model.CompanyModel;
import com.xbongbong.sys.model.DepartmentModel;
import com.xbongbong.sys.model.UserDepartmentModel;
import com.xbongbong.sys.model.UserModel;
import lombok.extern.slf4j.Slf4j;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

/**
 * 消息推送设置服务抽象类
 *
 * @author LiZhikang
 * @date 2022/11/1 16:37
 */

@Slf4j
public abstract class AbstractMessageSetService implements MessageSetService {

    @Resource
    protected PushSetModel pushSetModel;
    @Resource
    protected CompanyModel companyModel;
    @Resource
    protected LogHelp logHelp;
    @Resource
    protected MongoLogHelp mongoLogHelp;
    @Resource
    protected OperateLogModel operateLogModel;
    @Resource
    protected UserModel userModel;
    @Resource
    protected DepartmentModel departmentModel;
    @Resource
    protected UserDepartmentModel userDepartmentModel;

    @Override
    public MessageSetMenuListVO getMenuList(MessageSetMenuListDTO messageSetMenuListDTO) throws Exception {
        XbbRefTypeEnum xbbRefTypeEnum = XbbRefTypeEnum.getByAlias(messageSetMenuListDTO.getAlias());
        List<MessageMenuPojo> menuList = new ArrayList<>();
        List<MessageMenuTypeEnum> pushEnumList = MessageMenuTypeEnum.getAllEnumByType(xbbRefTypeEnum.getCode());
        pushEnumList.forEach(pushEnum -> menuList.add(new MessageMenuPojo(pushEnum.getSubCode(), pushEnum.getName())));
        return new MessageSetMenuListVO(menuList);
    }

    @Override
    public MessageSetSaveVO saveMessageSet(MessageSetSaveDTO messageSetSaveDTO) throws Exception {
        MessageSetSaveVO messageSetSaveVo = new MessageSetSaveVO();
        Long id = messageSetSaveDTO.getId();
        PushSetEntity pushSetEntity = new PushSetEntity();
        PushSetEntity oldPushSetEntity = null;
        if (Objects.equals(id, 0L)) {
            //新建
            pushSetEntity = new PushSetEntity();
            pushSetEntity.setCorpid(messageSetSaveDTO.getCorpid());
            pushSetEntity.setAttrEntity(messageSetSaveDTO.getAttrEntity());
            pushSetEntity.setType(messageSetSaveDTO.getType());
            pushSetEntity.setSubType(messageSetSaveDTO.getSubType());
            pushSetEntity.setEnable(messageSetSaveDTO.getEnable());
            pushSetEntity.setRefEntity(messageSetSaveDTO.getRefEntity());
            pushSetEntity.setTemplateId(messageSetSaveDTO.getTemplateId());
        } else {
            //编辑
            oldPushSetEntity = pushSetModel.getByKey(messageSetSaveDTO.getId(), messageSetSaveDTO.getCorpid());
            if (oldPushSetEntity == null) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100018, SystemErrorCodeEnum.API_ERROR_100018.getMsg());
            }
            BeanUtil.copyProperties(oldPushSetEntity, pushSetEntity);
        }
        pushSetEntity.setPushObject(messageSetSaveDTO.getPushObject());
        pushSetEntity.setPushTime(messageSetSaveDTO.getPushTime());
        messageSetSaveVo.setId(pushSetModel.save(pushSetEntity));

        if (Objects.equals(pushSetEntity.getEnable(), 1)) {
            CompanyEntity companyEntity = companyModel.getByKey(messageSetSaveDTO.getCorpid());
            companyEntity.setIsPushMessage(1);
            companyModel.update(companyEntity);
        }

        // 日志
        PushTypeEnum pushTypeEnum = PushTypeEnum.getPushTypeByCodeAndSubCode(pushSetEntity.getType(), pushSetEntity.getSubType());
        String memo;
        if (Objects.equals(id, 0L)) {
            memo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.MESSAGE_PUSH_SET_LOG_MEMO_ADD_SET), messageSetSaveDTO.getLoginUserName(), pushTypeEnum.getName());
            OperateLogEntity logEntity = new OperateLogEntity(messageSetSaveDTO.getCorpid(), messageSetSaveDTO.getUserId(), messageSetSaveDTO.getLoginUserName(), OperateModuleTypeEnum.MESASAGE_PUSH_SET,
                    OperateTypeEnum.NEW, pushSetEntity.getId().toString(), pushTypeEnum.getName(), memo, messageSetSaveDTO.getHttpHeader(), null);
            operateLogModel.insert(logEntity);
        } else {
            JSONObject oldObj = JsonHelperUtil.parseObject(JSONObject.toJSONString(oldPushSetEntity));
            JSONObject newObj = JsonHelperUtil.parseObject(JSONObject.toJSONString(pushSetEntity));

            memo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.MESSAGE_PUSH_SET_LOG_MEMO_EDIT_SET), messageSetSaveDTO.getLoginUserName(), pushTypeEnum.getName());
            List<DetailLogPojo> detailArr = logHelp.getDetailArr4Normal(messageSetSaveDTO.getCorpid(), OperateModuleTypeEnum.MESASAGE_PUSH_SET, oldObj, newObj);
            mongoLogHelp.buildLog4DetailArr(detailArr, messageSetSaveDTO.getCorpid(), messageSetSaveDTO.getUserId(), messageSetSaveDTO.getLoginUserName(), OperateModuleTypeEnum.MESASAGE_PUSH_SET, OperateTypeEnum.EDIT, id.toString(), pushTypeEnum.getName(), memo, messageSetSaveDTO.getHttpHeader());
        }
        return messageSetSaveVo;
    }

    @Override
    public MessageSetEnableVO enableMessageSet(MessageSetEnableDTO messageSetEnableDTO) throws Exception {
        MessageSetEnableVO messageSetEnableVO = new MessageSetEnableVO();
        PushSetEntity pushSetEntity = pushSetModel.getByKey(messageSetEnableDTO.getId(), messageSetEnableDTO.getCorpid());
        if (pushSetEntity == null) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100018, SystemErrorCodeEnum.API_ERROR_100018.getMsg());
        }
        pushSetEntity.setEnable(messageSetEnableDTO.getEnable());
        messageSetEnableVO.setId(pushSetModel.save(pushSetEntity));

        // 日志
        PushTypeEnum pushTypeEnum = PushTypeEnum.getPushTypeByCodeAndSubCode(pushSetEntity.getType(), pushSetEntity.getSubType());
        OperateTypeEnum operateTypeEnum = (Objects.equals(BasicConstant.NO_USE, messageSetEnableDTO.getEnable())) ? OperateTypeEnum.CLOSE : OperateTypeEnum.ENABLE;
        String enableStr = (Objects.equals(BasicConstant.NO_USE, messageSetEnableDTO.getEnable())) ? EnableEnum.CLOSE.getMemo() : EnableEnum.OPEN.getMemo();
        String memo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.MESSAGE_PUSH_SET_LOG_MEMO_ENABLE), messageSetEnableDTO.getLoginUserName() + enableStr, pushTypeEnum.getName());
        OperateLogEntity logEntity = new OperateLogEntity(messageSetEnableDTO.getCorpid(), messageSetEnableDTO.getUserId(), messageSetEnableDTO.getLoginUserName(), OperateModuleTypeEnum.MESASAGE_PUSH_SET,
                operateTypeEnum, pushSetEntity.getId().toString(), pushTypeEnum.getName(), memo, messageSetEnableDTO.getHttpHeader(), null);
        operateLogModel.insert(logEntity);
        return messageSetEnableVO;
    }

    /**
     * 通用的推送人员解析
     *
     * @param userEntity
     * @param pushObjectStr
     * @param typeUserIdList
     * @param date
     * @return
     */
    public List<String> getPushUserIdList(UserEntity userEntity, String pushObjectStr, List<String> typeUserIdList, Integer date) {
        if (Objects.isNull(pushObjectStr) || Objects.isNull(userEntity) || StringUtil.isEmpty(userEntity.getCorpid())) {
            return new ArrayList<>();
        }
        String corpid = userEntity.getCorpid();
        JSONObject pushObject = JSONObject.parseObject(pushObjectStr);

        Set<String> userIdSet = new HashSet<>();
        if (Objects.nonNull(typeUserIdList)) {
            userIdSet.addAll(typeUserIdList);
        }

        //销售简报推送不考虑推送对象类型，只解析指定的角色、部门、指定员工
        //角色处理
        Integer roleEnable = 0;
        List<Integer> roleIdList = new ArrayList<>();
        try {
            JSONObject roleObject = pushObject.getJSONObject("role");
            if (Objects.nonNull(roleObject)) {
                roleEnable = roleObject.getInteger("enable");
                if (Objects.equals(roleEnable, 1)) {
                    JSONArray roleArray = roleObject.getJSONArray("value");
                    for (Object object : roleArray) {
                        JSONObject jsonObject = (JSONObject) object;
                        roleIdList.add(jsonObject.getInteger("id"));
                    }
                }
            }
        } catch (Exception e) {
            log.warn("获取推送人列表时 role 解析失败");
        }
        if (CollectionsUtil.isNotEmpty(roleIdList)) {
            List<String> roleUserIds = userModel.getUserIdsByRoles(corpid, roleIdList);
            userIdSet.addAll(roleUserIds);
        }

        //部门处理
        List<Long> depIdList = new ArrayList<>();
        try {
            JSONObject depJsonObject = pushObject.getJSONObject("dep");
            if (Objects.nonNull(depJsonObject)) {
                Integer enable = depJsonObject.getInteger("enable");
                if (Objects.equals(enable, 1)) {
                    JSONArray depArray = depJsonObject.getJSONArray("value");
                    for (Object object : depArray) {
                        JSONObject jsonObject = (JSONObject) object;
                        depIdList.add(jsonObject.getLong("id"));
                    }
                }
            }
        } catch (Exception e) {
            log.warn("获取推送人列表时 dep 解析失败");
        }
        if (CollectionsUtil.isNotEmpty(depIdList)) {
            List<String> depUserIds = userModel.getUserIdsRecursionDep(depIdList, corpid);
            userIdSet.addAll(depUserIds);
        }

        //上级主管
        Integer managerEnable = 0;
        List<Integer> managerLevelList = new ArrayList<>();
        try {
            JSONObject managerObject = pushObject.getJSONObject("manager");
            if (Objects.nonNull(managerObject)) {
                managerEnable = managerObject.getInteger("enable");
                if (Objects.equals(managerEnable, 1)) {
                    JSONArray managerArray = managerObject.getJSONArray("value");
                    for (Object object : managerArray) {
                        JSONObject jsonObject = (JSONObject) object;
                        managerLevelList.add(jsonObject.getInteger("id"));
                    }
                }
            }
        } catch (Exception e) {
            log.warn("获取推送人列表时 manager 解析失败");
        }
        try {
            if (CollectionsUtil.isNotEmpty(managerLevelList)) {
                // 获取公司的所有
                List<String> depManagerIdList = getDepManagerIdList(corpid, userEntity, managerLevelList, departmentModel, userDepartmentModel);
                userIdSet.addAll(depManagerIdList);
            }
        } catch (Exception e) {
            log.error("获取部门时 manager 解析失败：corpid=" + corpid, e);
        }


        //指定人处理
        Integer userEnable = 0;
        List<String> userIdList = new ArrayList<>();
        try {
            JSONObject userObject = pushObject.getJSONObject("user");
            if (Objects.nonNull(userObject)) {
                userEnable = userObject.getInteger("enable");
                if (Objects.equals(userEnable, 1)) {
                    JSONArray userArray = userObject.getJSONArray("value");
                    for (Object object : userArray) {
                        JSONObject jsonObject = (JSONObject) object;
                        userIdList.add(jsonObject.getString("id"));
                    }
                }
            }
        } catch (Exception e) {
            log.warn("获取推送人列表时 user 解析失败");
        }
        if (CollectionsUtil.isNotEmpty(userIdList)) {
            userIdSet.addAll(userIdList);
        }

        //多选组件处理
        Integer multiEnable = 0;
        List<String> multiUserIdList = new ArrayList<>();
        List<Long> multiDeptIdList = new ArrayList<>();
        List<Integer> multiRoleIdList = new ArrayList<>();
        try {
            JSONObject multiObject = pushObject.getJSONObject("multi");
            if (Objects.nonNull(multiObject)) {
                multiEnable = multiObject.getInteger("enable");
                if (Objects.equals(multiEnable, 1)) {
                    JSONArray userArray = multiObject.getJSONArray("value");
                    for (Object object : userArray) {
                        JSONObject jsonObject = (JSONObject) object;
                        if (Objects.equals("user", jsonObject.getString("property"))) {
                            multiUserIdList.add(jsonObject.getString("id"));
                        } else if (Objects.equals("dept", jsonObject.getString("property"))) {
                            multiDeptIdList.add(jsonObject.getLong("id"));
                        } else if (Objects.equals("role", jsonObject.getString("property"))) {
                            multiRoleIdList.add(jsonObject.getInteger("id"));
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.warn("获取多选组件时 multi 解析失败");
        }
        if (Objects.equals(multiEnable, 1)) {
            if (CollectionsUtil.isNotEmpty(multiUserIdList)) {
                userIdSet.addAll(multiUserIdList);
            }
            if (CollectionsUtil.isNotEmpty(multiDeptIdList)) {
                userIdSet.addAll(userModel.getUserIdsRecursionDep(multiDeptIdList, corpid));
            }
            if (CollectionsUtil.isNotEmpty(multiRoleIdList)) {
                userIdSet.addAll(userModel.getUserIdsByRoles(corpid, multiRoleIdList));
            }
        }

        // 钊琦：推送时如果设置的推送名单包括操作人，也推送消息给操作人
        // 小于5分钟不推送给创建人
        if (date != null) {
            if ((date - DateUtil.getInt()) < 300) {
                userIdSet.remove(userEntity.getUserId());
            }
        }
        return new ArrayList<>(userIdSet);
    }

    /**
     * 上级主管解析
     *
     * @param userEntity
     * @param managerLevelList
     * @param departmentModel
     * @param userDepartmentModel
     * @return
     */
    private List<String> getDepManagerIdList(String corpid, UserEntity userEntity, List<Integer> managerLevelList,
                                             DepartmentModel departmentModel, UserDepartmentModel userDepartmentModel) throws XbbException{
        Integer maxLevel = 0;
        if (managerLevelList.size() > 0) {
            //获取最大值的部门等级 部门等级解释：假设a的所在的部门层级是 技术部-后端部-java部 ，那么a的一级部门就是 java部，2级部门就是后端部,3级部门就是技术部
            maxLevel = managerLevelList.stream().max(Comparator.comparing(Long::valueOf)).get();
        }

        List<DepartmentEntity> allDepList = departmentModel.findAllDepartment(corpid, false);
        Map<Long, DepartmentEntity> allDepMap = new HashMap<>();
        for (DepartmentEntity dep : allDepList) {
            allDepMap.put(dep.getId(), dep);
        }
        //user所在部门
        List<Long> userInDepIds = JSONObject.parseArray(userEntity.getDepartment(), Long.class);
        if (userInDepIds == null) {
            userInDepIds = new ArrayList<>();
        }
        //user是否是部门主管
        //key为部门id value表示是否是主管
        //找不到key对应的value、或key对应的value不是true表示非主管
        Set<DepartmentEntity> pointDepSet = null;
        Set<DepartmentEntity> managerDep = new HashSet<>();
        //获取层级managerLevelList对应的所有部门
        for (Integer i = 1; i < maxLevel + 1; i++) {
            if (i == 1) {
                //读取所在部门,第一次时，用所在部门初始化pointDepSet
                pointDepSet = new HashSet<>();
                for (Long depId : userInDepIds) {
                    DepartmentEntity tempDep = allDepMap.get(depId);

                    if (tempDep != null) {
                        pointDepSet.add(tempDep);
                    }
                }
                if (managerLevelList.contains(i)) {
                    managerDep.addAll(pointDepSet);
                }
                continue;
            }
            Set<DepartmentEntity> parentDepSet = new HashSet<>();
            for (DepartmentEntity dep : pointDepSet) {
                DepartmentEntity tempDep = allDepMap.get(dep.getParentId());
                if (tempDep != null) {
                    parentDepSet.add(tempDep);
                }
            }
            pointDepSet = parentDepSet;
            if (managerLevelList.contains(i)) {
                managerDep.addAll(pointDepSet);
            }
        }
        //获取完managerLevelList对应的所有部门
        List<Long> managerDepIdList = new ArrayList<>();
        for (DepartmentEntity dep : managerDep) {
            managerDepIdList.add(dep.getId());
        }
        List<UserDepartmentEntity> userDepList = new ArrayList<>();
        if (managerDepIdList.size() > 0) {
            Map<String, Object> params = new HashMap<>();
            params.put("corpid", corpid);
            params.put("departmentIdIn", managerDepIdList);
            params.put("isLeader", 1);
            params.put("del", 0);
            userDepList = userDepartmentModel.findEntitys(params);
        }

        List<String> depManagerIdList = new ArrayList<>();
        for (UserDepartmentEntity userDep : userDepList) {
            depManagerIdList.add(userDep.getUserId());
        }
        depManagerIdList.remove(userEntity.getUserId());

        return depManagerIdList;
    }

    /**
     * 人鱼去重
     *
     * @param userIds
     * @return
     */
    protected List<String> distinct(Object userIds) {
        Set<String> userIdsSet = new HashSet<>((List<String>) userIds);
        return new ArrayList<>(userIdsSet);
    }
}
